home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevpsds.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  18.2 KB  |  760 lines

  1. /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevpsds.c,v 1.4 2000/09/19 19:00:21 lpd Exp $ */
  20. /* Image processing streams for PostScript and PDF writers */
  21. #include "gx.h"
  22. #include "memory_.h"
  23. #include "gserrors.h"
  24. #include "gxdcconv.h"
  25. #include "gdevpsds.h"
  26.  
  27. /* ---------------- Convert between 1/2/4/12 and 8 bits ---------------- */
  28.  
  29. gs_private_st_simple(st_1248_state, stream_1248_state, "stream_1248_state");
  30.  
  31. /* Initialize an expansion or reduction stream. */
  32. int
  33. s_1248_init(stream_1248_state *ss, int Columns, int samples_per_pixel)
  34. {
  35.     ss->samples_per_row = Columns * samples_per_pixel;
  36.     return ss->template->init((stream_state *)ss);
  37. }
  38.  
  39. /* Initialize the state. */
  40. private int
  41. s_1_init(stream_state * st)
  42. {
  43.     stream_1248_state *const ss = (stream_1248_state *) st;
  44.  
  45.     ss->left = ss->samples_per_row;
  46.     ss->bits_per_sample = 1;
  47.     return 0;
  48. }
  49. private int
  50. s_2_init(stream_state * st)
  51. {
  52.     stream_1248_state *const ss = (stream_1248_state *) st;
  53.  
  54.     ss->left = ss->samples_per_row;
  55.     ss->bits_per_sample = 2;
  56.     return 0;
  57. }
  58. private int
  59. s_4_init(stream_state * st)
  60. {
  61.     stream_1248_state *const ss = (stream_1248_state *) st;
  62.  
  63.     ss->left = ss->samples_per_row;
  64.     ss->bits_per_sample = 4;
  65.     return 0;
  66. }
  67. private int
  68. s_12_init(stream_state * st)
  69. {
  70.     stream_1248_state *const ss = (stream_1248_state *) st;
  71.  
  72.     ss->left = ss->samples_per_row;
  73.     ss->bits_per_sample = 12;    /* not needed */
  74.     return 0;
  75. }
  76.  
  77. /* Process one buffer. */
  78. #define BEGIN_1248\
  79.     stream_1248_state * const ss = (stream_1248_state *)st;\
  80.     const byte *p = pr->ptr;\
  81.     const byte *rlimit = pr->limit;\
  82.     byte *q = pw->ptr;\
  83.     byte *wlimit = pw->limit;\
  84.     uint left = ss->left;\
  85.     int status;\
  86.     int n
  87. #define END_1248\
  88.     pr->ptr = p;\
  89.     pw->ptr = q;\
  90.     ss->left = left;\
  91.     return status
  92.  
  93. /* N-to-8 expansion */
  94. #define FOREACH_N_8(in, nout)\
  95.     status = 0;\
  96.     for ( ; p < rlimit; left -= n, q += n, ++p ) {\
  97.       byte in = p[1];\
  98.       n = min(left, nout);\
  99.       if ( wlimit - q < n ) {\
  100.         status = 1;\
  101.         break;\
  102.       }\
  103.       switch ( n ) {\
  104.         case 0: left = ss->samples_per_row; --p; continue;
  105. #define END_FOREACH_N_8\
  106.       }\
  107.     }
  108. private int
  109. s_N_8_process(stream_state * st, stream_cursor_read * pr,
  110.           stream_cursor_write * pw, bool last)
  111. {
  112.     BEGIN_1248;
  113.  
  114.     switch (ss->bits_per_sample) {
  115.  
  116.     case 1:{
  117.         FOREACH_N_8(in, 8)
  118.     case 8:
  119.         q[8] = (byte) - (in & 1);
  120.     case 7:
  121.         q[7] = (byte) - ((in >> 1) & 1);
  122.     case 6:
  123.         q[6] = (byte) - ((in >> 2) & 1);
  124.     case 5:
  125.         q[5] = (byte) - ((in >> 3) & 1);
  126.     case 4:
  127.         q[4] = (byte) - ((in >> 4) & 1);
  128.     case 3:
  129.         q[3] = (byte) - ((in >> 5) & 1);
  130.     case 2:
  131.         q[2] = (byte) - ((in >> 6) & 1);
  132.     case 1:
  133.         q[1] = (byte) - (in >> 7);
  134.         END_FOREACH_N_8;
  135.         }
  136.         break;
  137.  
  138.     case 2:{
  139.         static const byte b2[4] =
  140.         {0x00, 0x55, 0xaa, 0xff};
  141.  
  142.         FOREACH_N_8(in, 4)
  143.     case 4:
  144.         q[4] = b2[in & 3];
  145.     case 3:
  146.         q[3] = b2[(in >> 2) & 3];
  147.     case 2:
  148.         q[2] = b2[(in >> 4) & 3];
  149.     case 1:
  150.         q[1] = b2[in >> 6];
  151.         END_FOREACH_N_8;
  152.         }
  153.         break;
  154.  
  155.     case 4:{
  156.         static const byte b4[16] =
  157.         {
  158.             0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
  159.             0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
  160.         };
  161.  
  162.         FOREACH_N_8(in, 2)
  163.     case 2:
  164.         q[2] = b4[in & 0xf];
  165.     case 1:
  166.         q[1] = b4[in >> 4];
  167.         END_FOREACH_N_8;
  168.         }
  169.         break;
  170.  
  171.     default:
  172.         return ERRC;
  173.     }
  174.  
  175.     END_1248;
  176. }
  177.  
  178. /* 12-to-8 "expansion" */
  179. private int
  180. s_12_8_process(stream_state * st, stream_cursor_read * pr,
  181.            stream_cursor_write * pw, bool last)
  182. {
  183.     BEGIN_1248;
  184.  
  185.     n = ss->samples_per_row;    /* misuse n to avoid a compiler warning */
  186.     status = 0;
  187.     for (; rlimit - p >= 2; ++q) {
  188.     if (q >= wlimit) {
  189.         status = 1;
  190.         break;
  191.     }
  192.     if (left == 0)
  193.         left = n;
  194.     if ((n - left) & 1) {
  195.         q[1] = (byte)((p[1] << 4) | (p[2] >> 4));
  196.         p += 2, --left;
  197.     } else {
  198.         q[1] = *++p;
  199.         if (!--left)
  200.         ++p;
  201.     }
  202.     }
  203.  
  204.     END_1248;
  205. }
  206.  
  207.  
  208. /* 8-to-N reduction */
  209. #define FOREACH_8_N(out, nin)\
  210.     byte out;\
  211.     status = 1;\
  212.     for ( ; q < wlimit; left -= n, p += n, ++q ) {\
  213.       n = min(left, nin);\
  214.       if ( rlimit - p < n ) {\
  215.         status = 0;\
  216.         break;\
  217.       }\
  218.       out = 0;\
  219.       switch ( n ) {\
  220.         case 0: left = ss->samples_per_row; --q; continue;
  221. #define END_FOREACH_8_N\
  222.         q[1] = out;\
  223.       }\
  224.     }
  225. private int
  226. s_8_N_process(stream_state * st, stream_cursor_read * pr,
  227.           stream_cursor_write * pw, bool last)
  228. {
  229.     BEGIN_1248;
  230.  
  231.     switch (ss->bits_per_sample) {
  232.  
  233.     case 1:{
  234.         FOREACH_8_N(out, 8)
  235.     case 8:
  236.         out = p[8] >> 7;
  237.     case 7:
  238.         out |= (p[7] >> 7) << 1;
  239.     case 6:
  240.         out |= (p[6] >> 7) << 2;
  241.     case 5:
  242.         out |= (p[5] >> 7) << 3;
  243.     case 4:
  244.         out |= (p[4] >> 7) << 4;
  245.     case 3:
  246.         out |= (p[3] >> 7) << 5;
  247.     case 2:
  248.         out |= (p[2] >> 7) << 6;
  249.     case 1:
  250.         out |= p[1] & 0x80;
  251.         END_FOREACH_8_N;
  252.         }
  253.         break;
  254.  
  255.     case 2:{
  256.         FOREACH_8_N(out, 4)
  257.     case 4:
  258.         out |= p[4] >> 6;
  259.     case 3:
  260.         out |= (p[3] >> 6) << 2;
  261.     case 2:
  262.         out |= (p[2] >> 6) << 4;
  263.     case 1:
  264.         out |= p[1] & 0xc0;
  265.         END_FOREACH_8_N;
  266.         }
  267.         break;
  268.  
  269.     case 4:{
  270.         FOREACH_8_N(out, 2)
  271.     case 2:
  272.         out |= p[2] >> 4;
  273.     case 1:
  274.         out |= p[1] & 0xf0;
  275.         END_FOREACH_8_N;
  276.         }
  277.         break;
  278.  
  279.     default:
  280.         return ERRC;
  281.     }
  282.  
  283.     END_1248;
  284. }
  285.  
  286. const stream_template s_1_8_template = {
  287.     &st_1248_state, s_1_init, s_N_8_process, 1, 8
  288. };
  289. const stream_template s_2_8_template = {
  290.     &st_1248_state, s_2_init, s_N_8_process, 1, 4
  291. };
  292. const stream_template s_4_8_template = {
  293.     &st_1248_state, s_4_init, s_N_8_process, 1, 2
  294. };
  295. const stream_template s_12_8_template = {
  296.     &st_1248_state, s_12_init, s_12_8_process, 1, 2
  297. };
  298.  
  299. const stream_template s_8_1_template = {
  300.     &st_1248_state, s_1_init, s_8_N_process, 8, 1
  301. };
  302. const stream_template s_8_2_template = {
  303.     &st_1248_state, s_2_init, s_8_N_process, 4, 1
  304. };
  305. const stream_template s_8_4_template = {
  306.     &st_1248_state, s_4_init, s_8_N_process, 2, 1
  307. };
  308.  
  309. /* ---------------- Color space conversion ---------------- */
  310.  
  311. /* ------ Convert CMYK to RGB ------ */
  312.  
  313. private_st_C2R_state();
  314.  
  315. /* Initialize a CMYK => RGB conversion stream. */
  316. int
  317. s_C2R_init(stream_C2R_state *ss, const gs_imager_state *pis)
  318. {
  319.     ss->pis = pis;
  320.     return 0;
  321. }
  322.  
  323. /* Set default parameter values (actually, just clear pointers). */
  324. private void
  325. s_C2R_set_defaults(stream_state * st)
  326. {
  327.     stream_C2R_state *const ss = (stream_C2R_state *) st;
  328.  
  329.     ss->pis = 0;
  330. }
  331.  
  332. /* Process one buffer. */
  333. private int
  334. s_C2R_process(stream_state * st, stream_cursor_read * pr,
  335.           stream_cursor_write * pw, bool last)
  336. {
  337.     stream_C2R_state *const ss = (stream_C2R_state *) st;
  338.     const byte *p = pr->ptr;
  339.     const byte *rlimit = pr->limit;
  340.     byte *q = pw->ptr;
  341.     byte *wlimit = pw->limit;
  342.  
  343.     for (; rlimit - p >= 4 && wlimit - q >= 3; p += 4, q += 3) {
  344.     byte bc = p[1], bm = p[2], by = p[3], bk = p[4];
  345.     frac rgb[3];
  346.  
  347.     color_cmyk_to_rgb(byte2frac(bc), byte2frac(bm), byte2frac(by),
  348.               byte2frac(bk), ss->pis, rgb);
  349.     q[1] = frac2byte(rgb[0]);
  350.     q[2] = frac2byte(rgb[1]);
  351.     q[3] = frac2byte(rgb[2]);
  352.     }
  353.     pr->ptr = p;
  354.     pw->ptr = q;
  355.     return (rlimit - p < 4 ? 0 : 1);
  356. }
  357.  
  358. const stream_template s_C2R_template = {
  359.     &st_C2R_state, 0 /*NULL */ , s_C2R_process, 4, 3, 0, s_C2R_set_defaults
  360. };
  361.  
  362. /* ------ Convert any color space to Indexed ------ */
  363.  
  364. private_st_IE_state();
  365. private
  366. ENUM_PTRS_WITH(ie_state_enum_ptrs, stream_IE_state *st) return 0;
  367. case 0: return ENUM_OBJ(st->Decode);
  368. case 1: return ENUM_BYTESTRING(&st->Table);
  369. ENUM_PTRS_END
  370. private
  371. RELOC_PTRS_WITH(ie_state_reloc_ptrs, stream_IE_state *st)
  372. {
  373.     RELOC_VAR(st->Decode);
  374.     RELOC_BYTESTRING_VAR(st->Table);
  375. }
  376. RELOC_PTRS_END
  377.  
  378. /* Set defaults. */
  379. private void
  380. s_IE_set_defaults(stream_state * st)
  381. {
  382.     stream_IE_state *const ss = (stream_IE_state *) st;
  383.  
  384.     ss->Decode = 0;        /* clear pointers */
  385.     gs_bytestring_from_string(&ss->Table, 0, 0);
  386. }
  387.  
  388. /* Initialize the state. */
  389. private int
  390. s_IE_init(stream_state * st)
  391. {
  392.     stream_IE_state *const ss = (stream_IE_state *) st;
  393.     int key_index = (1 << ss->BitsPerIndex) * ss->NumComponents;
  394.     int i;
  395.  
  396.     if (ss->Table.data == 0 || ss->Table.size < key_index)
  397.     return ERRC;        /****** WRONG ******/
  398.     /* Initialize Table with default values. */
  399.     memset(ss->Table.data, 0, ss->NumComponents);
  400.     ss->Table.data[ss->Table.size - 1] = 0;
  401.     for (i = 0; i < countof(ss->hash_table); ++i)
  402.     ss->hash_table[i] = key_index;
  403.     ss->next_index = 0;
  404.     ss->in_bits_left = 0;
  405.     ss->next_component = 0;
  406.     ss->byte_out = 1;
  407.     ss->x = 0;
  408.     return 0;
  409. }
  410.  
  411. /* Process a buffer. */
  412. private int
  413. s_IE_process(stream_state * st, stream_cursor_read * pr,
  414.          stream_cursor_write * pw, bool last)
  415. {
  416.     stream_IE_state *const ss = (stream_IE_state *) st;
  417.     /* Constant values from the state */
  418.     const int bpc = ss->BitsPerComponent;
  419.     const int num_components = ss->NumComponents;
  420.     const int end_index = (1 << ss->BitsPerIndex) * num_components;
  421.     byte *const table = ss->Table.data;
  422.     byte *const key = table + end_index;
  423.     /* Dynamic values from the state */
  424.     uint byte_in = ss->byte_in;
  425.     int in_bits_left = ss->in_bits_left;
  426.     int next_component = ss->next_component;
  427.     uint byte_out = ss->byte_out;
  428.     /* Other dynamic values */
  429.     const byte *p = pr->ptr;
  430.     const byte *rlimit = pr->limit;
  431.     byte *q = pw->ptr;
  432.     byte *wlimit = pw->limit;
  433.     int status = 0;
  434.  
  435.     for (;;) {
  436.     uint hash, reprobe;
  437.     int i, index;
  438.  
  439.     /* Check for a filled output byte. */
  440.     if (byte_out >= 0x100) {
  441.         if (q >= wlimit) {
  442.         status = 1;
  443.         break;
  444.         }
  445.         *++q = (byte)byte_out;
  446.         byte_out = 1;
  447.     }
  448.     /* Acquire a complete input value. */
  449.     while (next_component < num_components) {
  450.         const float *decode = &ss->Decode[next_component * 2];
  451.         int sample;
  452.  
  453.         if (in_bits_left == 0) {
  454.         if (p >= rlimit)
  455.             goto out;
  456.         byte_in = *++p;
  457.         in_bits_left = 8;
  458.         }
  459.         /* An input sample can never span a byte boundary. */
  460.         in_bits_left -= bpc;
  461.         sample = (byte_in >> in_bits_left) & ((1 << bpc) - 1);
  462.         /* Scale the sample according to Decode. */
  463.         sample = (int)((decode[0] +
  464.                 (sample / (float)((1 << bpc) - 1) *
  465.                  (decode[1] - decode[0]))) * 255 + 0.5);
  466.         key[next_component++] =
  467.         (sample < 0 ? 0 : sample > 255 ? 255 : (byte)sample);
  468.     }
  469.     /* Look up the input value. */
  470.     for (hash = 0, i = 0; i < num_components; ++i)
  471.         hash = hash + 23 * key[i];  /* adhoc */
  472.     reprobe = (hash / countof(ss->hash_table)) | 137;  /* adhoc */
  473.     for (hash %= countof(ss->hash_table);
  474.          memcmp(table + ss->hash_table[hash], key, num_components);
  475.          hash = (hash + reprobe) % countof(ss->hash_table)
  476.          )
  477.         DO_NOTHING;
  478.     index = ss->hash_table[hash];
  479.     if (index == end_index) {
  480.         /* The match was on an empty entry. */
  481.         if (ss->next_index == end_index) {
  482.         /* Too many different values. */
  483.         status = ERRC;
  484.         break;
  485.         }
  486.         ss->hash_table[hash] = index = ss->next_index;
  487.         ss->next_index += num_components;
  488.         memcpy(table + index, key, num_components);
  489.     }
  490.     byte_out = (byte_out << ss->BitsPerIndex) + index / num_components;
  491.     next_component = 0;
  492.     if (++(ss->x) == ss->Width) {
  493.         /* Handle input and output padding. */
  494.         in_bits_left = 0;
  495.         if (byte_out != 1)
  496.         while (byte_out < 0x100)
  497.             byte_out <<= 1;
  498.         ss->x = 0;
  499.     }
  500.     }
  501. out:
  502.     pr->ptr = p;
  503.     pw->ptr = q;
  504.     ss->byte_in = byte_in;
  505.     ss->in_bits_left = in_bits_left;
  506.     ss->next_component = next_component;
  507.     ss->byte_out = byte_out;
  508.     /* For simplicity, always update the record of the table size. */
  509.     ss->Table.data[ss->Table.size - 1] =
  510.     (ss->next_index == 0 ? 0 :
  511.      ss->next_index / ss->NumComponents - 1);
  512.     return status;
  513. }
  514.  
  515. const stream_template s_IE_template = {
  516.     &st_IE_state, s_IE_init, s_IE_process, 1, 1,
  517.     0 /* NULL */, s_IE_set_defaults
  518. };
  519.  
  520. #if 0
  521.  
  522. /* Test code */
  523. void
  524. test_IE(void)
  525. {
  526.     const stream_template *const template = &s_IE_template;
  527.     stream_IE_state state;
  528.     stream_state *const ss = (stream_state *)&state;
  529.     static const float decode[6] = {1, 0, 1, 0, 1, 0};
  530.     static const byte in[] = {
  531.     /*
  532.      * Each row is 3 pixels x 3 components x 4 bits.  Processing the
  533.      * first two rows doesn't cause an error; processing all 3 rows
  534.      * does.
  535.      */
  536.     0x12, 0x35, 0x67, 0x9a, 0xb0,
  537.     0x56, 0x7d, 0xef, 0x12, 0x30,
  538.     0x88, 0x88, 0x88, 0x88, 0x80
  539.     };
  540.     byte table[3 * 5];
  541.     int n;
  542.  
  543.     template->set_defaults(ss);
  544.     state.BitsPerComponent = 4;
  545.     state.NumComponents = 3;
  546.     state.Width = 3;
  547.     state.BitsPerIndex = 2;
  548.     state.Decode = decode;
  549.     gs_bytestring_from_bytes(&state.Table, table, 0, sizeof(table));
  550.     for (n = 10; n <= 15; n += 5) {
  551.     stream_cursor_read r;
  552.     stream_cursor_write w;
  553.     byte out[100];
  554.     int status;
  555.  
  556.     s_IE_init(ss);
  557.     r.ptr = in; --r.ptr;
  558.     r.limit = r.ptr + n;
  559.     w.ptr = out; --w.ptr;
  560.     w.limit = w.ptr + sizeof(out);
  561.     memset(table, 0xcc, sizeof(table));
  562.     memset(out, 0xff, sizeof(out));
  563.     dprintf1("processing %d bytes\n", n);
  564.     status = template->process(ss, &r, &w, true);
  565.     dprintf3("%d bytes read, %d bytes written, status = %d\n",
  566.          (int)(r.ptr + 1 - in), (int)(w.ptr + 1 - out), status);
  567.     debug_dump_bytes(table, table + sizeof(table), "table");
  568.     debug_dump_bytes(out, w.ptr + 1, "out");
  569.     }
  570. }
  571.  
  572. #endif
  573.  
  574. /* ---------------- Downsampling ---------------- */
  575.  
  576. /* Return the number of samples after downsampling. */
  577. int
  578. s_Downsample_size_out(int size_in, int factor, bool pad)
  579. {
  580.     return ((pad ? size_in + factor - 1 : size_in) / factor);
  581. }
  582.  
  583. private void
  584. s_Downsample_set_defaults(register stream_state * st)
  585. {
  586.     stream_Downsample_state *const ss = (stream_Downsample_state *)st;
  587.  
  588.     s_Downsample_set_defaults_inline(ss);
  589. }
  590.  
  591. /* ------ Subsample ------ */
  592.  
  593. gs_private_st_simple(st_Subsample_state, stream_Subsample_state,
  594.              "stream_Subsample_state");
  595.  
  596. /* Initialize the state. */
  597. private int
  598. s_Subsample_init(stream_state * st)
  599. {
  600.     stream_Subsample_state *const ss = (stream_Subsample_state *) st;
  601.  
  602.     ss->x = ss->y = 0;
  603.     return 0;
  604. }
  605.  
  606. /* Process one buffer. */
  607. private int
  608. s_Subsample_process(stream_state * st, stream_cursor_read * pr,
  609.             stream_cursor_write * pw, bool last)
  610. {
  611.     stream_Subsample_state *const ss = (stream_Subsample_state *) st;
  612.     const byte *p = pr->ptr;
  613.     const byte *rlimit = pr->limit;
  614.     byte *q = pw->ptr;
  615.     byte *wlimit = pw->limit;
  616.     int spp = ss->Colors;
  617.     int width = ss->WidthIn, height = ss->HeightIn;
  618.     int xf = ss->XFactor, yf = ss->YFactor;
  619.     int xf2 = xf / 2, yf2 = yf / 2;
  620.     int xlimit = (width / xf) * xf, ylimit = (height / yf) * yf;
  621.     int xlast =
  622.     (ss->padX && xlimit < width ? xlimit + (width % xf) / 2 : -1);
  623.     int ylast =
  624.     (ss->padY && ylimit < height ? ylimit + (height % yf) / 2 : -1);
  625.     int x = ss->x, y = ss->y;
  626.     int status = 0;
  627.  
  628.     if_debug4('w', "[w]subsample: x=%d, y=%d, rcount=%ld, wcount=%ld\n",
  629.           x, y, (long)(rlimit - p), (long)(wlimit - q));
  630.     for (; rlimit - p >= spp; p += spp) {
  631.     if (((y % yf == yf2 && y < ylimit) || y == ylast) &&
  632.         ((x % xf == xf2 && x < xlimit) || x == xlast)
  633.         ) {
  634.         if (wlimit - q < spp) {
  635.         status = 1;
  636.         break;
  637.         }
  638.         memcpy(q + 1, p + 1, spp);
  639.         q += spp;
  640.     }
  641.     if (++x == width)
  642.         x = 0, ++y;
  643.     }
  644.     if_debug5('w',
  645.           "[w]subsample: x'=%d, y'=%d, read %ld, wrote %ld, status = %d\n",
  646.           x, y, (long)(p - pr->ptr), (long)(q - pw->ptr), status);
  647.     pr->ptr = p;
  648.     pw->ptr = q;
  649.     ss->x = x, ss->y = y;
  650.     return status;
  651. }
  652.  
  653. const stream_template s_Subsample_template = {
  654.     &st_Subsample_state, s_Subsample_init, s_Subsample_process, 4, 4,
  655.     0 /* NULL */, s_Downsample_set_defaults
  656. };
  657.  
  658. /* ------ Average ------ */
  659.  
  660. private_st_Average_state();
  661.  
  662. /* Set default parameter values (actually, just clear pointers). */
  663. private void
  664. s_Average_set_defaults(stream_state * st)
  665. {
  666.     stream_Average_state *const ss = (stream_Average_state *) st;
  667.  
  668.     s_Downsample_set_defaults(st);
  669.     /* Clear pointers */
  670.     ss->sums = 0;
  671. }
  672.  
  673. /* Initialize the state. */
  674. private int
  675. s_Average_init(stream_state * st)
  676. {
  677.     stream_Average_state *const ss = (stream_Average_state *) st;
  678.  
  679.     ss->sum_size =
  680.     ss->Colors * ((ss->WidthIn + ss->XFactor - 1) / ss->XFactor);
  681.     ss->copy_size = ss->sum_size -
  682.     (ss->padX || (ss->WidthIn % ss->XFactor == 0) ? 0 : ss->Colors);
  683.     ss->sums =
  684.     (uint *)gs_alloc_byte_array(st->memory, ss->sum_size,
  685.                     sizeof(uint), "Average sums");
  686.     if (ss->sums == 0)
  687.     return ERRC;    /****** WRONG ******/
  688.     memset(ss->sums, 0, ss->sum_size * sizeof(uint));
  689.     return s_Subsample_init(st);
  690. }
  691.  
  692. /* Release the state. */
  693. private void
  694. s_Average_release(stream_state * st)
  695. {
  696.     stream_Average_state *const ss = (stream_Average_state *) st;
  697.  
  698.     gs_free_object(st->memory, ss->sums, "Average sums");
  699. }
  700.  
  701. /* Process one buffer. */
  702. private int
  703. s_Average_process(stream_state * st, stream_cursor_read * pr,
  704.           stream_cursor_write * pw, bool last)
  705. {
  706.     stream_Average_state *const ss = (stream_Average_state *) st;
  707.     const byte *p = pr->ptr;
  708.     const byte *rlimit = pr->limit;
  709.     byte *q = pw->ptr;
  710.     byte *wlimit = pw->limit;
  711.     int spp = ss->Colors;
  712.     int width = ss->WidthIn;
  713.     int xf = ss->XFactor, yf = ss->YFactor;
  714.     int x = ss->x, y = ss->y;
  715.     uint *sums = ss->sums;
  716.     int status = 0;
  717.  
  718. top:
  719.     if (y == yf || (last && p >= rlimit && ss->padY && y != 0)) {
  720.     /* We're copying averaged values to the output. */
  721.     int ncopy = min(ss->copy_size - x, wlimit - q);
  722.  
  723.     if (ncopy) {
  724.         int scale = xf * y;
  725.  
  726.         while (--ncopy >= 0)
  727.         *++q = (byte) (sums[x++] / scale);
  728.     }
  729.     if (x < ss->copy_size) {
  730.         status = 1;
  731.         goto out;
  732.     }
  733.     /* Done copying. */
  734.     x = y = 0;
  735.     memset(sums, 0, ss->sum_size * sizeof(uint));
  736.     }
  737.     while (rlimit - p >= spp) {
  738.     uint *bp = sums + x / xf * spp;
  739.     int i;
  740.  
  741.     for (i = spp; --i >= 0;)
  742.         *bp++ += *++p;
  743.     if (++x == width) {
  744.         x = 0;
  745.         ++y;
  746.         goto top;
  747.     }
  748.     }
  749. out:
  750.     pr->ptr = p;
  751.     pw->ptr = q;
  752.     ss->x = x, ss->y = y;
  753.     return status;
  754. }
  755.  
  756. const stream_template s_Average_template = {
  757.     &st_Average_state, s_Average_init, s_Average_process, 4, 4,
  758.     s_Average_release, s_Average_set_defaults
  759. };
  760.